using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using SkinnedModel;

namespace A_stain_on_the_planet
{
    public class Seagull
    {
        Vector2 m_Position, m_velocity;
        Texture2D m_texSeagull;
        Texture2D m_texOil;
        Texture2D m_texPlons;
        Rectangle m_Rect;
        Rectangle m_RectOil;
        Vector2 m_BeginPoint;

        BoundingBox m_BoundingBox;
        SeagullLevel m_Level;
        SeagullLevelSurvival m_LevelSurvival;
        float m_Strenght;

        System.Random generator = new System.Random();
        ContentManager m_content;
        bool m_hasbeenswiped;
        bool m_isfree;
        bool m_LeftLooking;
        bool m_OilGone;
        bool m_FyingIn = false;
        bool m_Plons;
        bool m_Storymode;

        int m_FrameWidth = 123;
        int m_FrameHeight= 156;

        int m_FrameCount;
        int m_FrameAdd = 1;

        int m_FrameWidthOil = 215;
        int m_FrameHeightOil = 228;

        int m_FrameCountOil;

        int m_TimeTeller;
        int m_Plonsteller;
        int m_plonsframeX;
        int m_plonsFrameY;

        int m_StrenghtNeeded = 100;

        EventHandler m_Eventhandler;
        Model currentModel;
        Model m_ModelDrowning;
        Model m_ModelDrowningAlt;
        Model m_ModelFlying;
        Model m_ModelFlyingClean;
        AnimationPlayer animationPlayer;

        public Seagull(SeagullLevel Level, Vector2 Position, Texture2D texture, Texture2D Oil, bool left, int frame, EventHandler eventhandler)
        {
            m_Eventhandler = eventhandler;
            m_Level = Level;
            m_Position = Position;
            m_texSeagull = texture;
            m_texOil = Oil;
            m_LeftLooking = left;
            m_FrameCount = frame;
            m_Storymode = true;
        }

        public Seagull(SeagullLevelSurvival Level, Vector2 Position, Texture2D texture, Texture2D Oil, bool left, int frame, EventHandler eventhandler, bool story)
        {
            m_Eventhandler = eventhandler;
            m_LevelSurvival = Level;
            m_Position = Position;
            m_texSeagull = texture;
            m_texOil = Oil;
            m_LeftLooking = left;
            m_FrameCount = frame;
            m_Storymode = false;
        }

        public void Initialize(ContentManager content)
        {
            generator = new Random();

            int rand = generator.Next(0, 3);

            if (rand == 0)
            {
                m_ModelDrowning = content.Load<Model>(@"Animation\SeagullDrowning");
                m_ModelDrowningAlt = content.Load<Model>(@"Animation\SeagullDrowningAlt");
                m_ModelFlying = content.Load<Model>(@"Animation\SeagullFlying");
                m_ModelFlyingClean = content.Load<Model>(@"Animation\SeagullFlyingClean");
                currentModel = m_ModelDrowning;
            }

            if (rand == 1)
            {
                m_ModelDrowning = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Drown1_Recolor1");
                m_ModelDrowningAlt = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Drown2_Recolor1");
                m_ModelFlying = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Flying_Recolor1_Oil");
                m_ModelFlyingClean = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Flying_Recolor1_Clean");
                currentModel = m_ModelDrowning;
            }

            if (rand == 2)
            {
                m_ModelDrowning = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Drown1_Recolor2");
                m_ModelDrowningAlt = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Drown2_Recolor2");
                m_ModelFlying = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Flying_Recolor2_Oil");
                m_ModelFlyingClean = content.Load<Model>(@"Animation\INT2_Seagullslevel_Seagull_Flying_Recolor2_Clean");
                currentModel = m_ModelDrowning;
            }

            // Look up our custom skinning information.
            SkinningData skinningData = currentModel.Tag as SkinningData;

            if (skinningData == null)
                throw new InvalidOperationException
                    ("This model does not contain a SkinningData tag.");

            //Create an animation player, and start decoding an animation clip.
            animationPlayer = new AnimationPlayer(skinningData);

            AnimationClip clip = skinningData.AnimationClips["Take 001"];

            animationPlayer.StartClip(clip);

            m_velocity.X = 0.0f;
            m_velocity.Y = 0.0f;
            m_content = content;

            m_hasbeenswiped = false;

            float height = m_texSeagull.Height / 4.7f;

            int ImageHeight = (int)height;
            int ImageWidth = m_texSeagull.Width/16;
            
            m_Rect = new Rectangle((int)m_Position.X, (int)m_Position.Y, ImageWidth, ImageHeight);

            m_RectOil = new Rectangle((int)m_Position.X, (int)m_Position.Y, ImageWidth, ImageHeight);

            m_BoundingBox = new BoundingBox(new Vector3(m_Rect.X, m_Rect.Y, 0),
                                             new Vector3(m_Rect.X + m_Rect.Width, m_Rect.Y + m_Rect.Height, 0));

            m_texPlons = content.Load<Texture2D>(@"MainCharacters\Plunge_OilAnimatedSprite_V2");
        }

        public void Update(GameTime gametime)
        {
            animationPlayer.Update(gametime.ElapsedGameTime, true, Matrix.Identity);

            if (m_velocity.X == 0 && m_velocity.Y == 0)
            {
                m_Rect.X -= 1;
                m_RectOil = m_Rect;
                m_BeginPoint.X = m_Rect.X;
                m_BeginPoint.Y = m_Rect.Y;
            }

            else
            {
                if (m_LeftLooking == true)
                {
                    m_Rect.X += (int)m_velocity.X;
                    m_Rect.Y += (int)m_velocity.Y;


                    m_RectOil.Y = m_Rect.Y + m_Rect.Height / 2 - 10;
                    m_RectOil.X = m_Rect.X + m_Rect.Width / 2 - 20;
                    m_RectOil.Width = (int)m_BeginPoint.X - m_RectOil.X;
                    if (m_RectOil.Width <= 20) m_RectOil.Width = 20;
                    m_RectOil.Height = (int)m_BeginPoint.Y - (int)m_RectOil.Y + m_Rect.Height ;

                    int DistancefromOil = 200;

                    if (m_isfree == true)
                    {
                        if (m_RectOil.Y <= DistancefromOil)
                        {
                            m_OilGone = true;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 30)
                        {
                            m_FrameCountOil = 8;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 60)
                        {
                            m_FrameCountOil = 7;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 90)
                        {
                            m_FrameCountOil = 6;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 120)
                        {
                            m_FrameCountOil = 5;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 150)
                        {
                            m_FrameCountOil = 4;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 180)
                        {
                            m_FrameCountOil = 3;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 200)
                        {
                            m_FrameCountOil = 2;
                        }

                        else if (m_RectOil.Y <= DistancefromOil + 220)
                        {
                            m_FrameCountOil = 1;
                        }

                        else m_FrameCountOil = 0;
                    }

                    else m_FrameCountOil = 2;
                    
                }

                if (m_LeftLooking == false)
                {
                    m_Rect.X += (int)m_velocity.X;
                    m_Rect.Y += (int)m_velocity.Y;


                    m_RectOil.Y = m_Rect.Y + m_Rect.Height / 2 - 10;
                    m_RectOil.X = (int)m_BeginPoint.X;
                    m_RectOil.Width = m_Rect.X - m_RectOil.X + m_Rect.Width -10;
                    if (m_RectOil.Width <= 20) m_RectOil.Width = 20;
                    
                    m_RectOil.Height = (int)m_BeginPoint.Y - (int)m_RectOil.Y + m_Rect.Height + 50;

                    int DistancefromOil = 200;

                    if (m_RectOil.Y <= DistancefromOil)
                        {
                            m_OilGone = true;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 30)
                        {
                            m_FrameCountOil = 0;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 60)
                        {
                            m_FrameCountOil = 1;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 90)
                        {
                            m_FrameCountOil = 2;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 120)
                        {
                            m_FrameCountOil = 3;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 150)
                        {
                            m_FrameCountOil = 4;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 180)
                        {
                            m_FrameCountOil = 5;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 200)
                        {
                            m_FrameCountOil = 6;
                        }

                    else if (m_RectOil.Y <= DistancefromOil + 220)
                        {
                            m_FrameCountOil = 7;
                        }

                        else m_FrameCountOil = 8;
                    }
                
            }

            m_Position.X = m_Rect.X;
            m_Position.Y = m_Rect.Y;

            m_BoundingBox.Min.X = m_Rect.X;
            m_BoundingBox.Max.X = m_Rect.X + m_Rect.Width;

            m_BoundingBox.Min.Y = m_Rect.Y;
            m_BoundingBox.Max.Y = m_Rect.Y + m_Rect.Height;

            if ((m_Position.X < 0 && m_Position.Y == 370))
            {
                if (m_Storymode == true) m_Level.RemoveSeagull(this, false);
                else m_LevelSurvival.RemoveSeagull(this, false); 
            }

            if (m_Position.Y < 368 && m_Strenght >= m_StrenghtNeeded)
            {
                m_isfree = true;
            }

            if (m_Position.Y < 370 && m_Strenght < m_StrenghtNeeded)
            {
                m_velocity.Y += 0.2f;
            }

            if (m_Plons == true)
            {
                m_Plonsteller++;

                if (m_Plonsteller >= 3)
                {
                    m_Plonsteller =0;
                    ++m_plonsFrameY;
                    if (m_plonsFrameY >= 4)
                    {
                        m_plonsFrameY = 0;
                        ++m_plonsframeX;
                        if (m_plonsframeX >= 2)
                        {
                            m_plonsframeX = 0;
                            m_Plons = false;
                        }
                    }
                }
            }

            if (m_Position.Y >= 370 && m_FyingIn == true)
            {
                m_Plons = true;
                m_Eventhandler.SFXSSplash();
                m_velocity.Y = 0;
                m_velocity.X = 0;
                m_Position.Y = 370;
                m_Rect.Y = 370;
                m_hasbeenswiped = false;
                m_FyingIn = false;
            }

            else if(m_Position.Y >= 370)
            {
                m_velocity.Y = 0;
                m_velocity.X = 0;
                m_Position.Y = 370;
                m_Rect.Y = 370;
                m_hasbeenswiped = false;
                m_FyingIn = false;
            }

            if ((m_Position.Y < 0 || (m_Position.X < 0 && m_Position.Y != 350) || (m_Position.X > 800 && m_Position.Y != 350)) && m_isfree == true)
            {
                if (m_Storymode == true) m_Level.RemoveSeagull(this, true);
                else m_LevelSurvival.RemoveSeagull(this, true);
            }

            ++m_TimeTeller;

                if (m_TimeTeller >= 2)
                {
                    m_FrameCount += m_FrameAdd;

                    if (m_FrameCount <= 0)
                    {
                        m_FrameAdd = 1;
                    }

                    if (m_FrameCount >= 8)
                    {
                        m_FrameAdd = -1;
                    }

                    m_TimeTeller = 0;
                }
            

            if (m_velocity.X > 0) m_LeftLooking = false;
            if (m_velocity.X < 0) m_LeftLooking = true;
        }

        public void Draw(GameTime gametime, SpriteBatch spritebatch)
        {
            if (m_hasbeenswiped == true)
            {             
                if (currentModel != m_ModelFlying)
                {
                    currentModel = m_ModelFlying;

                    SkinningData skinningData = currentModel.Tag as SkinningData;

                    if (skinningData == null)
                        throw new InvalidOperationException
                            ("This model does not contain a SkinningData tag.");

                    //Create an animation player, and start decoding an animation clip.
                    animationPlayer = new AnimationPlayer(skinningData);

                    AnimationClip clip = skinningData.AnimationClips["Take 001"];

                    animationPlayer.StartClip(clip);
                }
            }

            else if (m_FyingIn == true)
            {
                
                if (currentModel != m_ModelFlyingClean)
                {
                    currentModel = m_ModelFlyingClean;

                    SkinningData skinningData = currentModel.Tag as SkinningData;

                    if (skinningData == null)
                        throw new InvalidOperationException
                            ("This model does not contain a SkinningData tag.");

                    //Create an animation player, and start decoding an animation clip.
                    animationPlayer = new AnimationPlayer(skinningData);

                    AnimationClip clip = skinningData.AnimationClips["Take 001"];

                    animationPlayer.StartClip(clip);
                }
            }

            else
            {
                if (m_Strenght > m_StrenghtNeeded/2)
                {
                    if (currentModel != m_ModelDrowning)
                    {
                        currentModel = m_ModelDrowning;

                        SkinningData skinningData = currentModel.Tag as SkinningData;

                        if (skinningData == null)
                            throw new InvalidOperationException
                                ("This model does not contain a SkinningData tag.");

                        //Create an animation player, and start decoding an animation clip.
                        animationPlayer = new AnimationPlayer(skinningData);

                        AnimationClip clip = skinningData.AnimationClips["Take 001"];

                        animationPlayer.StartClip(clip);

                        int rand = generator.Next(0, 600);

                        Matrix[] bones = animationPlayer.GetSkinTransforms();

                        TimeSpan time = new TimeSpan(0, 0, 0, 0, rand);

                        for (int i = 0; bones.Length >= i + 1; ++i)
                        {
                            animationPlayer.Update(time, true, bones[i]);
                        }
                    }

                }

                if (m_Strenght <= m_StrenghtNeeded/2)
                {
                    if (currentModel != m_ModelDrowningAlt)
                    {
                        currentModel = m_ModelDrowningAlt;

                        SkinningData skinningData = currentModel.Tag as SkinningData;

                        if (skinningData == null)
                            throw new InvalidOperationException
                                ("This model does not contain a SkinningData tag.");

                        //Create an animation player, and start decoding an animation clip.
                        animationPlayer = new AnimationPlayer(skinningData);

                        AnimationClip clip = skinningData.AnimationClips["Take 001"];

                        animationPlayer.StartClip(clip);

                        int rand = generator.Next(0, 600);

                        Matrix[] bones = animationPlayer.GetSkinTransforms();

                        TimeSpan time = new TimeSpan(0, 0, 0, 0, rand);

                        for (int i = 0; bones.Length >= i + 1; ++i)
                        {
                            animationPlayer.Update(time, true, bones[i]);
                        }
                    }
                }
            }

            if (m_Plons == true)
            {
                spritebatch.Draw(m_texPlons,new Rectangle((int)(m_Position.X - m_texPlons.Width/6), (int)(m_Position.Y - m_texPlons.Height/6 + 65), m_texPlons.Width/3,m_texPlons.Height/3)
                , new Rectangle((m_texPlons.Width / 2) * m_plonsframeX, (m_texPlons.Height / 4) * m_plonsFrameY, m_texPlons.Width / 2, m_texPlons.Height / 4), Color.White);
            }
        }

        public void AfterDraw(GameTime gametime, SpriteBatch spritebatch)
        {
            if (m_Plons == true)
            {
                spritebatch.Draw(m_texPlons, new Rectangle((int)(m_Position.X - m_texPlons.Width / 6), (int)(m_Position.Y - m_texPlons.Height / 6 + 65), m_texPlons.Width / 3, m_texPlons.Height / 3)
                , new Rectangle((m_texPlons.Width / 2) * m_plonsframeX, (m_texPlons.Height / 4) * m_plonsFrameY, m_texPlons.Width / 2, m_texPlons.Height / 4), Color.White);
            }
        }

        public Vector2 Position
        {
            get { return m_Position; }
            set { m_Position = value; } 
        }

        public Vector2 Velocity
        {
            get { return m_velocity; }
            set { m_velocity = value; }
        }

        public BoundingBox Boundingbox
        {
            get { return m_BoundingBox; }
        }
        public bool HasbeenSwiped
        {
            get { return m_hasbeenswiped; }
            set { m_hasbeenswiped = value; }
        }

        public void AddStrenght(float strenght,EventHandler eventhandler)
        {
            m_Strenght += strenght;
            if (m_Strenght >= m_StrenghtNeeded)
                eventhandler.SeagullFreed((int)Position.X-50, (int)Position.Y);
        }

        public float Strenght
        {
            get { return m_Strenght; }
        }

        public bool IsFlyingIn
        {
            get { return m_FyingIn; }
            set { m_FyingIn = value; }
        }

        public void Draw3D(GameTime gametime, GraphicsDeviceManager graphics)
        {
            GraphicsDevice device = graphics.GraphicsDevice;

            // Compute camera matrices.
            Matrix view = Matrix.CreateTranslation(0, 0, 0) *
                          Matrix.CreateRotationY(MathHelper.ToRadians(0)) *
                          Matrix.CreateRotationX(MathHelper.ToRadians(0)) *
                          Matrix.CreateLookAt(new Vector3(0, 0, 100),
                                              new Vector3(0, 0, 0), Vector3.Up);

            Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                                    device.Viewport.AspectRatio,
                                                                    1,
                                                                    10000);

            Matrix world;

            if (m_LeftLooking == true) world = Matrix.CreateRotationY((float)Math.PI);
            world = Matrix.CreateRotationY(0);

            if (currentModel == m_ModelFlyingClean || currentModel == m_ModelFlying) world *= Matrix.CreateRotationY((float)-(Math.PI/2));

            world *= Matrix.CreateScale(0.15f);

            float x = m_Position.X;
            x -= 400;
            x /= 400;
            x *= 70;
            x += 5;

            float y = m_Position.Y;
            y -= 250;
            y /= 250;
            y *= 43;
            y += 17;

            world.Translation = new Vector3(x, -y, 0);      

            Matrix[] bones = animationPlayer.GetSkinTransforms();
            //Render the skinned mesh.
            foreach (ModelMesh mesh in currentModel.Meshes)
            {
                foreach (SkinnedEffect effect in mesh.Effects)
                {
                    effect.SetBoneTransforms(bones);

                    effect.View = view;
                    effect.Projection = projection;

                    effect.EnableDefaultLighting();

                    effect.SpecularColor = new Vector3(0.25f);
                    effect.SpecularPower = 16;
                }

                //mesh.Draw();
            }
            
            currentModel.Draw(world, view, projection);
        }
    }
}
